// xWindow.cpp: Implementierung der Klasse xWindow.
//
//////////////////////////////////////////////////////////////////////

#include "xWindow.h"

extern int screenWidth;
extern int screenHeight;

extern int bitsperpixel;

#define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
#define GET_Y_LPARAM(lp) ((int)(short)HIWORD(lp))

//////////////////////////////////////////////////////////////////////
// Konstruktion/Destruktion
//////////////////////////////////////////////////////////////////////

xWindow::xWindow(const string &name) :

	hWnd(NULL),
	hInstance(NULL),
	
	actualx(0),actualy(0),
	actualheight(0),actualwidth(0),

	memoryDC(NULL),
	memoryBitmap(NULL),

	alwaysOnTop(false),
	visible(false),
	startHidden(false),

	painttexture(NULL),
	painttext(NULL)
{
	this->name = name;
}

xWindow::~xWindow()
{
	if (painttexture)
		Destroy_xTextureClass(painttexture);

	if (painttext)
		Destroy_xTextClass(painttext);

	if(memoryBitmap)
	{
		memoryBitmap = (HBITMAP) SelectObject(memoryDC, memoryBitmap);
		DeleteObject(memoryBitmap);
	}
	if(memoryDC)
		DeleteDC(memoryDC);

	memoryBitmap = NULL;
	memoryDC = NULL;

	if(IsWindow(hWnd))
	{
		DestroyWindow(hWnd);
		hWnd = 0;
	}
}

void xWindow::load(HINSTANCE hInstance)
{
	//Initial Repositioning
	actualx = GetxRCCoord(name.c_str(), "X", 0, screenWidth, false);
	actualy = GetxRCCoord(name.c_str(), "Y", 0, screenHeight, true);
	actualwidth = GetxRCDimen(name.c_str(), "Width", 64, screenWidth, false);
	actualheight = GetxRCDimen(name.c_str(), "Height", 64, screenHeight, true);

	startHidden = GetxRCBool(name.c_str(), "StartHidden");

	painttexture = Create_xTextureClass();
	painttext = Create_xTextClass();

	painttexture->configure(name.c_str(), "");
	painttext->configure(name.c_str(), "");

	hWnd = CreateWindowEx(  0 ,
							"xWindow",
							name.c_str(),
							WS_POPUP,
							actualx, actualy,		
							actualwidth,actualheight,
							GetLitestepWnd(), 
							0,
							hInstance,
							this);

	setAlwaysOnTop(GetxRCBool(name.c_str(), "AlwaysOnTop"), true);
 
	if ( hWnd )
	{
		SetWindowLong(hWnd, GWL_USERDATA, MAGIC_DWORD);

		updateRegion();
	}
	else
	{
		delete this;
	}
}

void xWindow::setAlwaysOnTop(bool setalwaysOnTop, bool firstSetup)
{
	bool realChange = ( alwaysOnTop != setalwaysOnTop );

	alwaysOnTop = setalwaysOnTop;
	
	if ( realChange || firstSetup )
	{
		ModifyStyle(hWnd, WS_POPUP, WS_CHILD);
		SetParent(hWnd, alwaysOnTop ? 0 : GetLitestepDesktop());
		ModifyStyle(hWnd, WS_CHILD, WS_POPUP);
	}

	SetWindowPos(hWnd, alwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
						0, 0, 0, 0,
						SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE );
}

void xWindow::hide()
{
	ShowWindow(hWnd, SW_HIDE);

	visible = false;
}

void xWindow::show()
{
	ShowWindow(hWnd, SW_SHOW);

	visible = true;
}

void xWindow::reposition(int type, int newx, int newy, int newwidth, int newheight, bool repositionBy)
{
	RECT rectPosition;
	rectPosition.left = actualx;
	rectPosition.right = actualx+actualwidth;
	rectPosition.top = actualy;
	rectPosition.bottom = actualy+actualheight;

	POINT posHolder;
	posHolder.x = rectPosition.left;
	posHolder.y = rectPosition.top;

	POINT sizeHolder;
	sizeHolder.x = (rectPosition.right-rectPosition.left);
	sizeHolder.y = (rectPosition.bottom-rectPosition.top);

	if (repositionBy)
	{
		if (type != 2)
		{
			newx = rectPosition.left + newx;
			newy = rectPosition.top + newy;
		}
		if (type != 1)
		{
			newwidth = (rectPosition.right-rectPosition.left) + newwidth;
			newheight = (rectPosition.bottom-rectPosition.top) + newheight;
		}
	}

	if ( type == 1 )
	{
		SetWindowPos(hWnd, 0, newx, newy, 0, 0,
						SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
	}
	else if ( type == 2 )
	{
		SetWindowPos(hWnd, 0, 0, 0, newwidth, newheight,
						SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
	}
	else if ( type == 3 )
	{
		SetWindowPos(hWnd, 0, newx, newy, newwidth, newheight,
						SWP_NOACTIVATE | SWP_NOZORDER);
	}
}

void xWindow::updateRegion()
{	
	if ( memoryBitmap != 0 && memoryDC != 0 )
	{
		RECT rectPosition;
		GetClientRect(hWnd, &rectPosition);

		HDC tmpDC = CreateCompatibleDC(NULL);
		HBITMAP tmpBmp = CreateBitmap(rectPosition.right, rectPosition.bottom, 1, bitsperpixel, NULL);
		HBITMAP oldBMP = (HBITMAP) SelectObject(tmpDC, tmpBmp);

		StretchBlt(tmpDC, 0, 0, rectPosition.right, rectPosition.bottom, memoryDC, 0, 0, actualwidth, actualheight, SRCCOPY);

		tmpBmp = (HBITMAP) SelectObject(tmpDC, oldBMP);

		HRGN region = BitmapToRegion(tmpBmp, RGB(255, 0, 255), 0, 0, 0);
		HRGN windowRgn = CreateRectRgn(0, 0, 0, 0);
		CombineRgn(windowRgn, region, NULL, RGN_COPY);

		SetWindowRgn(hWnd, windowRgn, true);	

		DeleteObject(windowRgn);
		DeleteObject(region);
		DeleteObject(tmpBmp);
		DeleteDC(tmpDC);
	}
}

void xWindow::onPaint(HDC hDC)
{	
	int x = actualx;
	int y = actualy;

	int width = actualwidth;
	int height = actualheight;

	RECT rectPosition;
	rectPosition.left = 0;
	rectPosition.top = 0;
	rectPosition.right = width;
	rectPosition.bottom = height;

	// Use Complete Backup for WindowsInternal Repaint (Covering Windows, ...)
	if ( memoryBitmap != 0 && memoryDC != 0 )
	{
		BitBlt(hDC, 0, 0, width, height, memoryDC, 0, 0, SRCCOPY);
	}
	else
	//1----------------------------------------------------------------
	{
	//1----------------------------------------------------------------
	
		memoryDC = CreateCompatibleDC(NULL);

		BITMAPINFO alpha;
		ZeroMemory( &alpha.bmiHeader, sizeof(BITMAPINFOHEADER) );
		alpha.bmiHeader.biWidth=width;      // Set size you need
		alpha.bmiHeader.biHeight=height;    // Set size you need
		alpha.bmiHeader.biPlanes=1;
		alpha.bmiHeader.biBitCount=32;      // Can be 8, 16, 32 bpp or other number
		alpha.bmiHeader.biSizeImage=0;
		alpha.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
		alpha.bmiHeader.biClrUsed= 0;
		alpha.bmiHeader.biClrImportant= 0;
		VOID *pvBits;

		memoryBitmap = CreateDIBSection( memoryDC,
											&alpha,
											DIB_RGB_COLORS,
											&pvBits,
											NULL,
											0 );

		SelectObject(memoryDC, memoryBitmap);

		//Magic Pink True Transparency
		::SetBkColor(memoryDC, RGB(255, 0, 255));
		::ExtTextOut(memoryDC, 0, 0, ETO_OPAQUE, &rectPosition, NULL, 0, NULL);
				
		//Background Painting
		painttexture->apply(memoryDC, 0, 0, width, height);

		painttext->apply(memoryDC, 0, 0, width, height, "This is a Template :)");

		BitBlt(hDC, 0, 0, width, height, memoryDC, 0, 0, SRCCOPY);
	}
}

LRESULT xWindow::windowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	xWindow *xwindow = NULL;

	if (message == WM_NCCREATE)
	{
		xwindow = (xWindow *) ((CREATESTRUCT *) lParam)->lpCreateParams;
		xwindow->hWnd = hWnd;
		SetWindowLong(hWnd, 0, (LONG) xwindow);
	}
	else
	{
		xwindow = (xWindow *) GetWindowLong(hWnd, 0);
	}

	if (xwindow)
	{
		LRESULT lResult = 0;

		if ( xwindow->onWindowMessage(message, wParam, lParam, lResult) )
			return lResult;
	}

	return DefWindowProc(hWnd, message, wParam, lParam);
}


bool xWindow::onWindowMessage(UINT message, WPARAM wParam, LPARAM lParam, LRESULT &lResult)
{
	lResult = 0;

	switch(message)
	{
		case WM_CLOSE:
		{
			lResult = 0;
			return true;
		}

		case WM_PAINT:
		{
			PAINTSTRUCT ps;

			HDC hDC;

			hDC = BeginPaint( hWnd, &ps );

			onPaint( hDC );
			
			EndPaint( hWnd, &ps );

			return true;
		}

		case WM_SIZE:
		{
			if(memoryBitmap)
			{
				memoryBitmap = (HBITMAP) SelectObject(memoryDC, memoryBitmap);
				DeleteObject(memoryBitmap);
			}
			if(memoryDC)
				DeleteDC(memoryDC);

			memoryBitmap = NULL;
			memoryDC = NULL;

			updateRegion();
			return true;
		}
	}

	return false;
}

